package cli;

import java.util.List;

import shared.Category;
import shared.Mode;
import cli.menu.AddExpense;
import cli.menu.AddIncome;
import cli.menu.GeneralReport;
import cli.menu.TrackExpenses;

public class CommandParser{
	
	private static CLI cli;
	
	public CommandParser(CLI c){
		cli= c;	
	}
	
	public static void printSimpleList(List wantedList){
		//hides Loan Payment category
		if(wantedList.get(0).getClass() == Category.class)
			wantedList.remove(1);
	//	cli.println(wantedList.size() + " items");
		String temp;
		for(int i = 0; i < wantedList.size(); i++){
			temp = wantedList.get(i).toString() + "                       ";
			temp = temp.substring(0, 20);
			cli.print(temp);
			if(i%4 == 3){
				cli.println();
			}	
		}
		if(wantedList.size()%4 != 0){
			cli.println();
		}
	}
	
	public static boolean checkPeriod(String input){
		input = input.trim();
		if(input.equalsIgnoreCase("day") || input.equalsIgnoreCase("month") || input.equalsIgnoreCase("year"))
			return true;
		return false;
	}
	
	
	//	0    1     	          2         						  3          4					
	// add expense 		paymentmethod 						category	 name/price/date/details
	// add expense		loan								category	 name/price/lender/details
	// add cashloan 	name/amount/lender/date/details
	// add income 		name/amt/details
	// add category 	name
	// add paymentmode 	name
	//general [day or month or year]
	   
	public boolean parse(String command){
	
	//Pattern date = Pattern.compile("\\d{1,2}\\.\\d{1,2}\\.\\d{4}");
	
		//checks for single word commands first
		if(command.trim().equalsIgnoreCase("exit")){
			cli.terminate();
		}
		
	//split the command into the main components to identify what command it is
	String[] process = command.split(" ");
	
	//invalid command
	if(process.length < 2){
	cli.println("Insufficient information provided");
	return false;
	}
	
	String operator = process[0];
	String subject = process[1];
	
	//if it is to access general report - 2 fields minimum
	if(operator.equalsIgnoreCase("general")){
		if(checkPeriod(subject)){
		GeneralReport.printGeneralReport(1, subject);
		return true;
		}
		cli.println("Incorrect period provided: " + subject);
		cli.println("Valid periods are: day, month, year");
		return false;
	}
	
	//new? function : list
	if(operator.equalsIgnoreCase("list")){	
		List wantedList = null;
		if(subject.equalsIgnoreCase("category"))
			wantedList = cli.getApi().getCategoryList();
		else if(subject.equalsIgnoreCase("Mode"))
			wantedList = cli.getApi().getModeList();
		if(wantedList!=null){
			printSimpleList(wantedList);
			return true;
		}
		else{
			cli.println(subject + " could not be found");
		}	
	}
	
	//if it is to  track [expense/receipt] [period]
	//if 2nd field missing, treat as expense tracking
	//TODO : track receipt
	if(operator.equalsIgnoreCase("track")){	
		if(process.length < 3){
			if(process.length == 2 && checkPeriod(process[1])){
				TrackExpenses.printTrackExpense(process[1],false);
				return true;
			}
			else{
			cli.println("Insufficient information provided");
			return false;
			}
		}
		
		if(subject.equalsIgnoreCase("expense")){
			if(checkPeriod(process[2])){
				TrackExpenses.printTrackExpense(process[1],false);
				return true;
			}
		}
		
		cli.println("No such option for track exist");
		return false;
	}
	
	
	//if it is an add operation
	if(operator.equalsIgnoreCase("add")){	
		//invalid command : add commands need 3 fields minimum
		if(process.length < 3){
		cli.println("Insufficient information provided");
		return false;
		}
		if(subject.equalsIgnoreCase("expense"))
			return addExpenseHelper(process);	
		if(subject.equalsIgnoreCase("income"))
			return addIncomeHelper(process);
		if(subject.equalsIgnoreCase("category"))
			return addCategoryHelper(process[2]);
		if(subject.equalsIgnoreCase("paymentmode"))
			return addPaymentModeHelper(process[2]);
	}	
	 return false;
	}
	
	
	private static boolean addPaymentModeHelper(String modeName){
		try{
			cli.getApi().addMode(modeName);
			return true;
			}
			catch(Exception e){
				cli.println("Failed to add a new Payment Mode with name: " + modeName);
				return false;
			}
		
	}
	private static boolean addCategoryHelper(String catName){
		
		try {
			cli.getApi().addCategory(catName);
			return true;
//			cli.println("New category added: " + catName);
		} catch (Exception e) {
			cli.println("Failed to add a new category: " + catName);
			return false;
		}
		
	}
	
	private static boolean addExpenseHelper(String[] process){
		
//		String subject = process[1];
		
	//	if(subject.equalsIgnoreCase("expense")){
			if(process.length < 4){
			cli.print("Insufficient information provided");
			return false;
			}
			
		String modeName = process[2];
		Mode paymentMode = null;
		List<Mode> modeList = cli.getApi().getModeList();
		for(Mode m : modeList){
			if(modeName.equalsIgnoreCase(m.getName())){
			paymentMode = m;
			break;
			}
		}
		
		//if there was no mode with that mentioned name
		//add it 
		if(paymentMode == null){
				try{
			paymentMode= cli.getApi().addMode(modeName);
			}
			catch(Exception e){
				cli.println("Failed to add a new Payment Mode with name: " + modeName);
				return false;
			}
	
		}
		
		//payment mode settled, now for category
		 String catName = process[3];
		 Category category = null;
		  List<Category> catList = cli.getApi().getCategoryList();
		  //remove the Loan Payment category (so that it's not selectable / invisible)
		 catList.remove(1);
		 if(catName.equalsIgnoreCase("Loan Payment")){
		 cli.println("You are not allowed to add an expense into 'Loan Payment' category");
		 cli.println("Relocating to Uncategorised...");
		 category = catList.get(0);
		 }
		
		 Category cat;
		 for(int i = 0; i < catList.size(); i++){
			 cat = catList.get(i);
//			 cli.println(cat.getName());
			if(catName.equalsIgnoreCase(cat.getName())){
			category = cat;
			break;
			}
		}
		
		//if we can't find an existing category with that name, create a new one
		if(category == null){
		try {
			category = cli.getApi().addCategory(catName);
		//	cli.println("New category added: " + catName);
		} catch (Exception e) {
			cli.println("Failed to add a new category: " + catName);
			return false;
		}
		}
		
		
		//process mainbody (info / data)
		 //String mainBody = process[4];
		String mainBody = "";
		for(int i = 4; i < process.length; i++)
			mainBody += process[i];
		 
		 if(!paymentMode.getName().equalsIgnoreCase("Loan")){
			 if(AddExpense.receiveExpenseEntry(mainBody, paymentMode, category)){
				 cli.println("New expense added");
				 return true;
			 }
		 }
		 else{
			 if(AddExpense.receiveLoanEntry(mainBody, category)){
				 cli.println("New expense added");
				 return true;
			 }
		 }
		 
		
	
		return false;

	}
	
	private static boolean addIncomeHelper(String[] process){
		
		String data = "";
		for(int i = 2; i < process.length; i++)
			data+=process[i];
		AddIncome.normFunction(data);
		cli.println("New income added");
		return true;
	}
	
	
}
